<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="scripts/vue.js"></script>
    <script src="scripts/element.min.js"></script>
    <link rel="stylesheet" href="css/index.css">
    <script src="scripts/axios.js"></script>
    <script src="scripts/hls.js"></script>

    <style>
        /* 页面基础样式 */
        body {
            font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
            background: #f5f7fa;
            margin: 0;
            padding: 20px;
            color: #333;
        }

        #app {
            max-width: 1200px;
            margin: 0 auto;
        }

        .top-bar {
            background: #409EFF;
            color: white;
            padding: 0 20px;
            height: 60px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15);
        }

        .user-info {
            display: flex;
            align-items: center;
            gap: 10px;
        }

        .login-btn {
            background: white;
            color: #409EFF;
            border: none;
            padding: 8px 15px;
            border-radius: 4px;
            cursor: pointer;
            font-weight: 500;
        }

        /* 登录弹窗样式 */
        .login-dialog {
            background: white;
            padding: 20px;
            border-radius: 8px;
            width: 400px;
            box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15);
        }

        .login-form-item {
            margin-bottom: 20px;
        }

        /* 上传区域样式 */
        .upload-section {
            background: #fff;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
            margin-bottom: 30px;
        }

        /* 缩略图控制样式 */
        .vedio-item .shot {
            width: 100%;
            height: 150px;
            object-fit: cover;
            border-radius: 6px 6px 0 0;
        }

        .vedio-item .title {
            padding: 12px;
            text-align: center;
            font-weight: 500;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }

        /* 视频项布局 */
        .vedio-item {
            display: flex;
            flex-direction: column;
            cursor: pointer;
            transition: all 0.3s;
            background: #fff;
            border-radius: 6px;
            overflow: hidden;
            box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
        }

        .vedio-item:hover {
            transform: translateY(-5px);
            box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
        }

        /* 网格布局 */
        .vedio-list {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
            gap: 20px;
        }

        /* 进度条样式 */
        .progress-container {
            margin: 20px 0;
        }

        /* 播放器区域样式 */
        .player-container {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.9);
            z-index: 1000;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            opacity: 0;
            pointer-events: none;
            transition: opacity 0.3s ease;
        }

        .player-container.active {
            opacity: 1;
            pointer-events: all;
        }

        .player-wrapper {
            width: 80%;
            max-width: 900px;
            position: relative;
        }

        .player-wrapper video {
            width: 100%;
            border-radius: 8px;
            background: #000;
        }

        .close-btn {
            position: absolute;
            top: 20px;
            right: 20px;
            background: #fff;
            width: 40px;
            height: 40px;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            cursor: pointer;
            font-size: 20px;
            font-weight: bold;
            z-index: 1001;
            transition: all 0.2s;
        }

        .close-btn:hover {
            background: #f56c6c;
            color: white;
            transform: scale(1.1);
        }

        .video-title {
            color: white;
            font-size: 18px;
            margin-top: 15px;
            text-align: center;
        }

        .upload-controls {
            display: flex;
            gap: 10px;
            margin-top: 15px;
        }
    </style>
</head>

<body>
    <div id="app">
        <div class="top-bar">
            <div class="user-info" v-if="userInfo">
                <span>{{ userInfo.username }}</span>
                <span>(ID: {{ userInfo.userId }})</span>
                <el-button type="danger" size="small" @click="logout">退出</el-button>
            </div>
            <button v-else class="login-btn" @click="showLoginDialog">登录</button>
        </div>

        <div class="upload-section">
            <input type="file" @change="handleFileChange" />
            <div class="upload-controls">
                <el-button @click="handleUpload" :disabled="!container.file">上传</el-button>
                <el-button @click="handlePause" :disabled="percentage === 0">暂停</el-button>
                <el-button @click="resume" :disabled="percentage === 0">继续</el-button>
            </div>
            <div class="progress-container">
                <el-progress :percentage="percentage" status="success"></el-progress>
            </div>
        </div>

        <div class="vedio-list">
            <div v-for="vedio in vedios" :key="vedio.id" class="vedio-item" @click="play(vedio)">
                <div class="thumb-container">
                    <img :src="vedio.imgPath" alt="缩略图" class="shot">
                </div>
                <div class="title">{{ vedio.fileName }}</div>
            </div>
        </div>

        <!-- HLS播放器容器 -->
        <div class="player-container" :class="{ active: isPlaying }">
            <div class="player-wrapper">
                <div class="close-btn" @click="closePlayer">×</div>
                <video id="hls-video" controls autoplay></video>
                <div class="video-title">{{ currentVideoTitle }}</div>
            </div>
        </div>

        <!-- 登录弹窗 -->
        <el-dialog title="用户登录" :visible.sync="loginDialogVisible" width="30%">
            <div class="login-dialog">
                <div class="login-form-item">
                    <el-input v-model="loginForm.username" placeholder="用户名"></el-input>
                </div>
                <div class="login-form-item">
                    <el-input v-model="loginForm.password" type="password" placeholder="密码"></el-input>
                </div>
                <el-button type="primary" @click="handleLogin" style="width: 100%">登录</el-button>
            </div>
        </el-dialog>
    </div>
</body>

<script>
    // JWT解析函数
    function parseJwt(token) {
        try {
            const base64Url = token.split('.')[1];
            const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
            const jsonPayload = decodeURIComponent(atob(base64).split('').map(c =>
                '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
            ).join(''));

            return JSON.parse(jsonPayload);
        } catch (e) {
            return null;
        }
    }

    // 设置请求拦截器，添加Authorization头
    axios.interceptors.request.use(config => {
        const token = localStorage.getItem('token');
        if (token) {
            config.headers.Authorization = `Bearer ${token}`;
        }
        return config;
    }, error => {
        return Promise.reject(error);
    });

    new Vue({
        el: "#app",
        data() {
            return {
                // 用户相关状态
                userInfo: null,
                loginDialogVisible: false,
                loginForm: {
                    username: '',
                    password: ''
                },

                paused: false,
                container: {
                    file: null,
                    hash: null,
                },
                vedios: [],
                data: [],        // 切片数据
                percentage: 0,   // 上传总进度
                uploaded: 0,    // 上传的切片
                requestList: [], // 请求控制器列表
                cancelTokenList: [], // axios取消令牌列表
                isPlaying: false, // 是否正在播放
                currentVideoTitle: '' // 当前播放视频标题
            }
        },
        created() {
            this.getAll();
            this.checkLoginStatus(); // 检查登录状态
        },
        methods: {
            // 检查登录状态
            checkLoginStatus() {
                const token = localStorage.getItem('token');
                if (token) {
                    const payload = parseJwt(token);
                    if (payload) {
                        this.userInfo = {
                            userId: payload.userid,  // 注意payload中的字段名是小写userid
                            username: payload.username
                        };
                    }
                }
            },

            // 显示登录对话框
            showLoginDialog() {
                this.loginDialogVisible = true;
            },

            // 处理登录
            handleLogin() {
                const formData = new FormData
                formData.append("username", this.loginForm.username)
                formData.append("password", this.loginForm.password)
                axios.post('http://127.0.0.1:8080/gateway/user/login', formData)
                    .then(response => {
                        console.log(response)
                        if (response.data.token) {
                            // 保存token到localStorage
                            localStorage.setItem('token', response.data.token);

                            // 解析用户信息
                            const payload = parseJwt(response.data.token);
                            this.userInfo = {
                                userId: payload.userid,
                                username: payload.username
                            };

                            this.loginDialogVisible = false;
                            this.$message.success('登录成功');
                        }
                    })
                    .catch(error => {
                        this.$message.error('登录失败: ' + (error.response?.data?.message || '未知错误'));
                    });
            },

            // 退出登录
            logout() {
                localStorage.removeItem('token');
                this.userInfo = null;
                this.$message.success('已退出登录');
            },
            // 处理文件选择
            handleFileChange(e) {
                const [file] = e.target.files;
                if (!file) {
                    this.container.file = null;
                    return;
                }
                this.container.file = file;
            },
            getAll() {
                axios.get('http://127.0.0.1:8000/vedios/all').then((res) => {
                    this.vedios = res.data
                })
            },
            calculateHash(files) {
                return new Promise((resolve, reject) => {
                    // 创建 Blob URL 替代外部 worker 文件
                    const script = `
var hexcase = 0;
var b64pad = "";

function hex_md5(s) { return rstr2hex(rstr_md5(str2rstr_utf8(s))); }
function b64_md5(s) { return rstr2b64(rstr_md5(str2rstr_utf8(s))); }
function any_md5(s, e) { return rstr2any(rstr_md5(str2rstr_utf8(s)), e); }
function hex_hmac_md5(k, d) { return rstr2hex(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); }
function b64_hmac_md5(k, d) { return rstr2b64(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); }
function any_hmac_md5(k, d, e) { return rstr2any(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d)), e); }

function md5_vm_test() {
    return hex_md5("abc").toLowerCase() == "900150983cd24fb0d6963f7d28e17f72";
}

function rstr_md5(s) {
    return binl2rstr(binl_md5(rstr2binl(s), s.length * 8));
}

function rstr_hmac_md5(key, data) {
    var bkey = rstr2binl(key);
    if (bkey.length > 16) bkey = binl_md5(bkey, key.length * 8);

    var ipad = Array(16), opad = Array(16);
    for (var i = 0; i < 16; i++) {
        ipad[i] = bkey[i] ^ 0x36363636;
        opad[i] = bkey[i] ^ 0x5C5C5C5C;
    }

    var hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
    return binl2rstr(binl_md5(opad.concat(hash), 512 + 128));
}

function rstr2hex(input) {
    try { hexcase } catch (e) { hexcase = 0; }
    var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
    var output = "";
    var x;
    for (var i = 0; i < input.length; i++) {
        x = input.charCodeAt(i);
        output += hex_tab.charAt((x >>> 4) & 0x0F)
            + hex_tab.charAt(x & 0x0F);
    }
    return output;
}

function rstr2b64(input) {
    try { b64pad } catch (e) { b64pad = ''; }
    var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    var output = "";
    var len = input.length;
    for (var i = 0; i < len; i += 3) {
        var triplet = (input.charCodeAt(i) << 16)
            | (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0)
            | (i + 2 < len ? input.charCodeAt(i + 2) : 0);
        for (var j = 0; j < 4; j++) {
            if (i * 8 + j * 6 > input.length * 8) output += b64pad;
            else output += tab.charAt((triplet >>> 6 * (3 - j)) & 0x3F);
        }
    }
    return output;
}

function rstr2any(input, encoding) {
    var divisor = encoding.length;
    var i, j, q, x, quotient;

    var dividend = Array(Math.ceil(input.length / 2));
    for (i = 0; i < dividend.length; i++) {
        dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
    }

    var full_length = Math.ceil(input.length * 8 /
        (Math.log(encoding.length) / Math.log(2)));
    var remainders = Array(full_length);
    for (j = 0; j < full_length; j++) {
        quotient = Array();
        x = 0;
        for (i = 0; i < dividend.length; i++) {
            x = (x << 16) + dividend[i];
            q = Math.floor(x / divisor);
            x -= q * divisor;
            if (quotient.length > 0 || q > 0)
                quotient[quotient.length] = q;
        }
        remainders[j] = x;
        dividend = quotient;
    }

    var output = "";
    for (i = remainders.length - 1; i >= 0; i--)
        output += encoding.charAt(remainders[i]);

    return output;
}

function str2rstr_utf8(input) {
    var output = "";
    var i = -1;
    var x, y;

    while (++i < input.length) {
        x = input.charCodeAt(i);
        y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
        if (0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) {
            x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
            i++;
        }

        if (x <= 0x7F)
            output += String.fromCharCode(x);
        else if (x <= 0x7FF)
            output += String.fromCharCode(0xC0 | ((x >>> 6) & 0x1F),
                0x80 | (x & 0x3F));
        else if (x <= 0xFFFF)
            output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
                0x80 | ((x >>> 6) & 0x3F),
                0x80 | (x & 0x3F));
        else if (x <= 0x1FFFFF)
            output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
                0x80 | ((x >>> 12) & 0x3F),
                0x80 | ((x >>> 6) & 0x3F),
                0x80 | (x & 0x3F));
    }
    return output;
}

function str2rstr_utf16le(input) {
    var output = "";
    for (var i = 0; i < input.length; i++)
        output += String.fromCharCode(input.charCodeAt(i) & 0xFF,
            (input.charCodeAt(i) >>> 8) & 0xFF);
    return output;
}

function str2rstr_utf16be(input) {
    var output = "";
    for (var i = 0; i < input.length; i++)
        output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
            input.charCodeAt(i) & 0xFF);
    return output;
}

function rstr2binl(input) {
    var output = Array(input.length >> 2);
    for (var i = 0; i < output.length; i++)
        output[i] = 0;
    for (var i = 0; i < input.length * 8; i += 8)
        output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << (i % 32);
    return output;
}

function binl2rstr(input) {
    var output = "";
    for (var i = 0; i < input.length * 32; i += 8)
        output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xFF);
    return output;
}

function binl_md5(x, len) {
    /* append padding */
    x[len >> 5] |= 0x80 << ((len) % 32);
    x[(((len + 64) >>> 9) << 4) + 14] = len;

    var a = 1732584193;
    var b = -271733879;
    var c = -1732584194;
    var d = 271733878;

    for (var i = 0; i < x.length; i += 16) {
        var olda = a;
        var oldb = b;
        var oldc = c;
        var oldd = d;

        a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936);
        d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);
        c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
        b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);
        a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);
        d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
        c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);
        b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);
        a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
        d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);
        c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);
        b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
        a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
        d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
        c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
        b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);

        a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);
        d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);
        c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
        b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302);
        a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);
        d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
        c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
        b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);
        a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
        d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);
        c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);
        b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
        a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);
        d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);
        c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
        b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);

        a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);
        d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);
        c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
        b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
        a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);
        d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
        c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);
        b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
        a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
        d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222);
        c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);
        b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
        a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);
        d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
        c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
        b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);

        a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844);
        d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
        c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
        b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);
        a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
        d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);
        c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
        b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);
        a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
        d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
        c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);
        b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
        a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);
        d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
        c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
        b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);

        a = safe_add(a, olda);
        b = safe_add(b, oldb);
        c = safe_add(c, oldc);
        d = safe_add(d, oldd);
    }
    return Array(a, b, c, d);
}

function md5_cmn(q, a, b, x, s, t) {
    return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);
}
function md5_ff(a, b, c, d, x, s, t) {
    return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
}
function md5_gg(a, b, c, d, x, s, t) {
    return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
}
function md5_hh(a, b, c, d, x, s, t) {
    return md5_cmn(b ^ c ^ d, a, b, x, s, t);
}
function md5_ii(a, b, c, d, x, s, t) {
    return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
}

function safe_add(x, y) {
    var lsw = (x & 0xFFFF) + (y & 0xFFFF);
    var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
    return (msw << 16) | (lsw & 0xFFFF);
}

function bit_rol(num, cnt) {
    return (num << cnt) | (num >>> (32 - cnt));
}

function buffer2Binary(buffer) {
    const bytes = new Uint8Array(buffer);
    let binary = '';
    for (let i = 0; i < bytes.byteLength; i++) {
        binary += String.fromCharCode(bytes[i]);
    }
    return binary;
}

self.onmessage=function(e){
    let data = e.data;

    if (data instanceof ArrayBuffer)
        data = buffer2Binary(data);
    const hash = hex_md5(data);
    self.postMessage(hash)
}
`;

                    const blob = new Blob([script], { type: 'application/javascript' });
                    const workerUrl = URL.createObjectURL(blob);
                    const worker = new Worker(workerUrl);

                    const read = file => {
                        return new Promise((resolve, reject) => {
                            const reader = new FileReader();
                            reader.onload = e => resolve(e.target.result);
                            reader.onerror = reject;
                            reader.readAsArrayBuffer(file);
                        });
                    };

                    // 读取单个文件
                    read(files)
                        .then(buffer => {
                            // 直接发送文件的 ArrayBuffer 给 Worker
                            worker.postMessage(buffer);
                        })
                        .catch(error => {
                            reject(error);
                            URL.revokeObjectURL(workerUrl);
                        });

                    worker.onmessage = e => {
                        if (e.data.error)
                            reject(e.data.error)
                        const hash = e.data;

                        if (hash) {
                            URL.revokeObjectURL(workerUrl); // 清理Worker
                            resolve(hash);
                        }
                    };
                });
            },
            async getVideoLength(file) {
                return new Promise((resolve, reject) => {
                    const url = URL.createObjectURL(file);
                    const videoElement = document.createElement('video');

                    videoElement.addEventListener('loadedmetadata', () => {
                        URL.revokeObjectURL(url);
                        resolve(Math.round(videoElement.duration));
                    });

                    videoElement.addEventListener('error', (e) => {
                        URL.revokeObjectURL(url);
                        reject(new Error('无法加载视频元数据'));
                    });
                    videoElement.src = url;
                });
            },
            // 上传处理
            async handleUpload() {
                if (!localStorage.getItem('token')) {
                    this.showLoginDialog();
                    this.$message.warning('请先登录');
                    return;
                }

                if (!this.container.file) return;
                try {
                    this.container.hash = await this.calculateHash(this.container.file);
                    const formData = new FormData();

                    formData.append('hash', this.container.hash);
                    formData.append('userId', this.userInfo.userId); // 添加用户ID
                    var duration

                    await this.getVideoLength(this.container.file).then(res => {
                        duration = res
                    }).catch(error => {
                        console.error(error);
                    });

                    uploadTime = Date.now();

                    axios.post('http://127.0.0.1:8000/vedios/upload/check', formData).then((res) => {
                        if (res.status == 200)
                            this.$message.success('上传成功');

                        else {
                            const chunks = this.createFileChunk(this.container.file);
                            this.data = chunks.map(({ index, chunk }) => ({
                                index,
                                chunk,
                                hash: `${this.container.hash}`
                            }));
                            console.log(this.container.hash)
                            const total = this.data.length;
                            const userId = this.userInfo ? this.userInfo.userId : null;
                            const metadata = new FormData
                            metadata.append('userid', userId); // 添加用户ID
                            metadata.append('title', "test");
                            metadata.append('duration', duration);
                            metadata.append('uploadtime', uploadTime);
                            metadata.append('total', total);  // 总分片数
                            metadata.append('hash', this.container.hash);
                            metadata.append('filename', this.container.file.name);
                            axios.post('http://127.0.0.1:8000/vedios/upload/metadata', metadata).then(res => {
                                if (res.status == 201 || res.status == 200)
                                    this.uploadChunks()
                            })
                            // this.mergeRequest();
                        }
                    })
                }
                catch (error) {
                    console.error("上传失败:", error);
                }
            },

            // 生成文件切片
            createFileChunk(file, size = 1 * 1024 * 1024) {
                const chunks = [];
                let cur = 0;
                while (cur < file.size) {
                    chunks.push({
                        index: chunks.length + 1,//不从0开始
                        chunk: file.slice(cur, cur + size)
                    });
                    cur += size;
                }
                return chunks;
            },
            // 切片上传
            async uploadChunks() {
                // 重置进度
                this.cancelTokenList = [];

                // 添加用户ID到每个请求
                const userId = this.userInfo ? this.userInfo.userId : null;
                if (!userId) {
                    this.$message.error('用户信息缺失，请重新登录');
                    return;
                }

                const total = this.data.length;

                this.percentage = Math.round((this.uploaded / (this.data.length - 1)) * 100);

                const chunks = this.data.filter((d) => d.index > this.uploaded)
                // 生成上传请求
                const requests = chunks.map(item => {
                    const formData = new FormData();
                    formData.append('file', item.chunk);
                    formData.append('hash', item.hash);
                    formData.append('filename', this.container.file.name);
                    formData.append('size', item.chunk.size);  // 分片文件大小
                    formData.append('total', total);  // 总分片数
                    formData.append('index', item.index);  // 当前分片索引

                    // 创建取消令牌
                    const source = axios.CancelToken.source();
                    this.cancelTokenList.push(source);

                    return axios.post('http://127.0.0.1:8000/vedios/chunk/upload', formData, {
                        cancelToken: source.token,
                        // 上传进度回调
                        onUploadProgress: progress => {
                            item.progress = Math.min(
                                Math.round((progress.loaded / progress.total) * 100),
                                100
                            );
                            const completed = this.data.filter(i => i.progress === 100).length;
                            this.percentage = Math.round((completed / total) * 100);
                        }
                    }).then(res => {
                        console.log("分片" + item.index + "已上传")
                        this.uploaded = item.index
                    });
                });
                await Promise.all(requests);
            },

            // 合并请求
            async mergeRequest() {
                const formData = new FormData();

                formData.append('filename', this.container.file.name);
                formData.append('hash', this.container.hash);
                formData.append('total', this.data.length);  // 总分片数
                console.log(this.container.file.name)

                await axios.post('http://127.0.0.1:8000/vedios/chunk/merge', formData).then(res => {
                    console.log(res)
                });
                this.$message.success('上传成功');
            },

            // 暂停上传
            handlePause() {
                this.cancelTokenList.forEach(source => {
                    source.cancel('用户暂停上传');
                });
                this.cancelTokenList = []
            },

            resume() {
                this.uploadChunks()
            },

            // 播放视频
            async play(vedio) {
                this.isPlaying = true;
                this.currentVideoTitle = vedio.fileName;

                // 先获取视频URL
                try {
                    const formData = new FormData();
                    formData.append('filename', vedio.fileName);
                    const res = await axios.post('http://127.0.0.1:8000/vedios/play', formData);
                    const vedioUrl = res.data;
                    console.log('获取到的视频URL:', vedioUrl); // 调试：确认URL格式

                    // 确保DOM更新完成后再操作video元素
                    await new Promise(resolve => this.$nextTick(resolve));

                    const video = document.getElementById('hls-video');
                    video.src = '';

                    // 使用hls.js播放HLS视频
                    if (Hls.isSupported()) {
                        const hls = new Hls();
                        // {
                        //     xhrSetup: (xhr) => {
                        //         // 确保HLS请求设置withCredentials
                        //         xhr.withCredentials = true;
                        //     }
                        // }
                        hls.loadSource(vedioUrl);
                        hls.attachMedia(video);

                        hls.on(Hls.Events.MANIFEST_PARSED, () => {
                            video.play().catch(error => {
                                console.error('播放失败:', error);
                            });
                        });

                        // 处理可能的跨域错误
                        hls.on(Hls.Events.ERROR, (_, data) => {
                            if (data.type === Hls.ErrorTypes.NETWORK_ERROR) {
                                console.error('网络错误，请检查CORS配置:', data.details);
                                alert('视频加载失败：网络错误');
                            }
                        });
                    }
                    // 原生支持HLS的情况
                    else if (video.canPlayType('application/vnd.apple.mpegurl')) {
                        video.src = vedioUrl;
                        video.addEventListener('loadedmetadata', () => {
                            video.play().catch(error => {
                                console.error('播放失败:', error);
                            });
                        });
                    } else
                        alert('您的浏览器不支持播放HLS视频');
                } catch (error) {
                    console.error('视频加载失败:', error);
                    alert('视频加载失败: ' + error.message);
                }
            },

            // 关闭播放器
            closePlayer() {
                this.isPlaying = false;
                const video = document.getElementById('hls-video');
                video.pause();
                video.src = '';
            }
        }
    })
</script>

</html>